D:\a\tools.proto\tools.proto\dynamic\src\component\factory.rs
Line | Count | Source |
1 | | // Copyright (c) 2025, BlockProject 3D |
2 | | // |
3 | | // All rights reserved. |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without modification, |
6 | | // are permitted provided that the following conditions are met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright notice, |
9 | | // this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above copyright notice, |
11 | | // this list of conditions and the following disclaimer in the documentation |
12 | | // and/or other materials provided with the distribution. |
13 | | // * Neither the name of BlockProject 3D nor the names of its contributors |
14 | | // may be used to endorse or promote products derived from this software |
15 | | // without specific prior written permission. |
16 | | // |
17 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
21 | | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 | | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
23 | | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
24 | | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
25 | | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
26 | | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | |
29 | | use std::cell::RefCell; |
30 | | use std::collections::HashMap; |
31 | | use std::hash::{Hash, Hasher}; |
32 | | use std::rc::Rc; |
33 | | use crate::component::ComponentType; |
34 | | use bp3d_util::{simple_error, try_opt}; |
35 | | use bp3d_protoc::compiler::structure::FixedFieldType; |
36 | | use bp3d_protoc::model::protocol::Endianness; |
37 | | |
38 | | simple_error! { |
39 | | pub Error { |
40 | | AlreadyRegistered(String) => "factory for component '{}' is already registered", |
41 | | NotFound(String) => "component name '{}' not found", |
42 | | Fail(String) => "factory for component name '{}' has failed" |
43 | | } |
44 | | } |
45 | | |
46 | | pub type Result<T> = std::result::Result<T, Error>; |
47 | | |
48 | | #[derive(Copy, Clone, Eq, PartialEq, Hash)] |
49 | | pub enum SizeType { |
50 | | U8, |
51 | | U16LE, |
52 | | U16BE, |
53 | | U32LE, |
54 | | U32BE, |
55 | | U64LE, |
56 | | U64BE |
57 | | } |
58 | | |
59 | | impl SizeType { |
60 | 0 | pub fn get_endianness(&self) -> Endianness { |
61 | 0 | match self { |
62 | 0 | SizeType::U16LE | SizeType::U32LE | SizeType::U64LE => Endianness::Little, |
63 | 0 | _ => Endianness::Big |
64 | | } |
65 | 0 | } |
66 | | |
67 | 0 | pub fn get_size(&self) -> usize { |
68 | 0 | match self { |
69 | 0 | SizeType::U8 => 1, |
70 | 0 | SizeType::U16LE | SizeType::U16BE => 2, |
71 | 0 | SizeType::U32LE | SizeType::U32BE => 4, |
72 | 0 | SizeType::U64LE | SizeType::U64BE => 8 |
73 | | } |
74 | 0 | } |
75 | | } |
76 | | |
77 | | impl From<(FixedFieldType, Endianness)> for SizeType { |
78 | 0 | fn from((value, endianness): (FixedFieldType, Endianness)) -> Self { |
79 | 0 | match (value, endianness) { |
80 | 0 | (FixedFieldType::Int8 | FixedFieldType::UInt8 | FixedFieldType::Bool, _) => SizeType::U8, |
81 | 0 | (FixedFieldType::Int16 | FixedFieldType::UInt16, Endianness::Little) => SizeType::U16LE, |
82 | 0 | (FixedFieldType::Int16 | FixedFieldType::UInt16, Endianness::Big) => SizeType::U16BE, |
83 | 0 | (FixedFieldType::Int32 | FixedFieldType::UInt32 | FixedFieldType::Float32, Endianness::Little) => SizeType::U32LE, |
84 | 0 | (FixedFieldType::Int32 | FixedFieldType::UInt32 | FixedFieldType::Float32, Endianness::Big) => SizeType::U32BE, |
85 | 0 | (FixedFieldType::Int64 | FixedFieldType::UInt64 | FixedFieldType::Float64, Endianness::Little) => SizeType::U64LE, |
86 | 0 | (FixedFieldType::Int64 | FixedFieldType::UInt64 | FixedFieldType::Float64, Endianness::Big) => SizeType::U64BE |
87 | | } |
88 | 0 | } |
89 | | } |
90 | | |
91 | | pub struct ContainerOptions { |
92 | | pub inner_ty: Rc<dyn ComponentType>, |
93 | | pub count_ty: SizeType, |
94 | | pub size_ty: Option<SizeType> |
95 | | } |
96 | | |
97 | | impl ContainerOptions { |
98 | | #[inline(always)] |
99 | 0 | fn inner_ty_ptr(&self) -> usize { |
100 | 0 | let key = self.inner_ty.key(); |
101 | 0 | if key != 0 { Branch (101:12): [Folded - Ignored]
Branch (101:12): [True: 0, False: 0]
|
102 | 0 | key |
103 | | } else { |
104 | 0 | Rc::as_ptr(&self.inner_ty) as *const () as _ |
105 | | } |
106 | 0 | } |
107 | | } |
108 | | |
109 | | impl Eq for ContainerOptions {} |
110 | | |
111 | | impl PartialEq for ContainerOptions { |
112 | 0 | fn eq(&self, other: &Self) -> bool { |
113 | 0 | self.inner_ty_ptr() == other.inner_ty_ptr() && self.count_ty == other.count_ty && self.size_ty == other.size_ty Branch (113:9): [Folded - Ignored]
Branch (113:56): [Folded - Ignored]
Branch (113:9): [True: 0, False: 0]
Branch (113:56): [True: 0, False: 0]
|
114 | 0 | } |
115 | | } |
116 | | |
117 | | impl Hash for ContainerOptions { |
118 | 0 | fn hash<H: Hasher>(&self, state: &mut H) { |
119 | 0 | state.write_usize(self.inner_ty_ptr()); |
120 | 0 | self.count_ty.hash(state); |
121 | 0 | self.size_ty.hash(state); |
122 | 0 | } |
123 | | } |
124 | | |
125 | | #[derive(Eq, PartialEq, Hash)] |
126 | | enum CompKeyInner { |
127 | | Container(ContainerOptions), |
128 | | Buffer(Option<SizeType>) |
129 | | } |
130 | | |
131 | | #[derive(Eq, PartialEq, Hash)] |
132 | | pub struct Key { |
133 | | name: String, |
134 | | inner: CompKeyInner |
135 | | } |
136 | | |
137 | | impl Key { |
138 | 0 | pub fn for_container(name: impl Into<String>, options: ContainerOptions) -> Self { |
139 | 0 | Self { |
140 | 0 | name: name.into(), |
141 | 0 | inner: CompKeyInner::Container(options) |
142 | 0 | } |
143 | 0 | } |
144 | | |
145 | 6 | pub fn for_buffer(name: impl Into<String>, size: Option<SizeType>) -> Self { |
146 | 6 | Self { |
147 | 6 | name: name.into(), |
148 | 6 | inner: CompKeyInner::Buffer(size) |
149 | 6 | } |
150 | 6 | } |
151 | | } |
152 | | |
153 | | pub struct Factory { |
154 | | container_factories: HashMap<String, Box<dyn Fn(&ContainerOptions) -> Option<Rc<dyn ComponentType>>>>, |
155 | | buffer_factories: HashMap<String, Box<dyn Fn(Option<SizeType>) -> Option<Rc<dyn ComponentType>>>>, |
156 | | components: RefCell<HashMap<Key, Rc<dyn ComponentType>>> |
157 | | } |
158 | | |
159 | | impl Factory { |
160 | 4 | pub fn new() -> Self { |
161 | 4 | Self { |
162 | 4 | container_factories: HashMap::new(), |
163 | 4 | buffer_factories: HashMap::new(), |
164 | 4 | components: RefCell::new(HashMap::new()) |
165 | 4 | } |
166 | 4 | } |
167 | | |
168 | 0 | pub fn add_container_factory<F: Fn(&ContainerOptions) -> Option<Rc<dyn ComponentType>> + 'static>(&mut self, component_name: impl Into<String>, factory: F) -> Result<()> { |
169 | 0 | let component_name = component_name.into(); |
170 | 0 | if self.container_factories.contains_key(&component_name) && self.buffer_factories.contains_key(&component_name) { Branch (170:12): [Folded - Ignored]
Branch (170:70): [Folded - Ignored]
Branch (170:12): [Folded - Ignored]
Branch (170:70): [Folded - Ignored]
|
171 | 0 | return Err(Error::AlreadyRegistered(component_name)); |
172 | 0 | } |
173 | 0 | self.container_factories.insert(component_name.clone(), Box::new(factory)); |
174 | 0 | Ok(()) |
175 | 0 | } |
176 | | |
177 | 0 | pub fn add_buffer_factory<F: Fn(Option<SizeType>) -> Option<Rc<dyn ComponentType>> + 'static>(&mut self, component_name: impl Into<String>, factory: F) -> Result<()> { |
178 | 0 | let component_name = component_name.into(); |
179 | 0 | if self.container_factories.contains_key(&component_name) && self.buffer_factories.contains_key(&component_name) { Branch (179:12): [Folded - Ignored]
Branch (179:70): [Folded - Ignored]
Branch (179:12): [Folded - Ignored]
Branch (179:70): [Folded - Ignored]
|
180 | 0 | return Err(Error::AlreadyRegistered(component_name)); |
181 | 0 | } |
182 | 0 | self.buffer_factories.insert(component_name.clone(), Box::new(factory)); |
183 | 0 | Ok(()) |
184 | 0 | } |
185 | | |
186 | 2 | pub fn add_component(&mut self, key: Key, component: impl ComponentType + 'static) -> Result<()> { |
187 | 2 | if self.components.get_mut().contains_key(&key) { Branch (187:12): [Folded - Ignored]
Branch (187:12): [Folded - Ignored]
Branch (187:12): [True: 0, False: 1]
Branch (187:12): [True: 0, False: 1]
|
188 | 0 | return Err(Error::AlreadyRegistered(key.name)); |
189 | 2 | } |
190 | 2 | self.components.get_mut().insert(key, Rc::new(component)); |
191 | 2 | Ok(()) |
192 | 2 | } |
193 | | |
194 | 4 | pub fn with_component<R>(&self, key: Key, f: impl FnOnce(&Rc<dyn ComponentType>) -> R) -> Result<R> { |
195 | 4 | let mut components = self.components.borrow_mut(); |
196 | 4 | if let Some(component) = components.get(&key) { Branch (196:16): [Folded - Ignored]
Branch (196:16): [True: 0, False: 0]
Branch (196:16): [True: 4, False: 0]
Branch (196:16): [True: 0, False: 0]
Branch (196:16): [True: 0, False: 0]
Branch (196:16): [True: 0, False: 0]
Branch (196:16): [True: 0, False: 0]
|
197 | 4 | return Ok(f(&*component)); |
198 | 0 | } |
199 | 0 | let ct = match &key.inner { |
200 | 0 | CompKeyInner::Container(opts) => self.container_factories.get(&key.name).map(|v| v(opts)), |
201 | 0 | CompKeyInner::Buffer(opt) => self.buffer_factories.get(&key.name).map(|v| v(*opt)) |
202 | | }; |
203 | 0 | let ct = try_opt!(try_opt!(ct => Error::NotFound(key.name)) => Error::Fail(key.name)); |
204 | 0 | let component = components.entry(key).or_insert(ct); |
205 | 0 | Ok(f(component)) |
206 | 4 | } |
207 | | |
208 | 0 | pub fn get_component(&self, key: Key) -> Result<Rc<dyn ComponentType>> { |
209 | 0 | self.with_component(key, |c| c.clone()) |
210 | 0 | } |
211 | | } |